前言

  • Android开发中,网络请求十分常用
  • 当下的网络请求加载库中,Retrofit则是当下hottest的一个网络请求库

简介

特别注意:

  • 准确来说,Retrofit是一个 RESTful 的 HTTP 网络请求框架的封装
  • 原因:网络请求的工作本质上是OkHttp完成的,而Retrofit仅负责网络请求接口的封装
  • App应用程序通过 Retrofit 请求网络,实际上是使用Retrofit接口层封装请求参数、Header、Url等信息,之后由OkHttp完成后续的请求操作
  • 在服务端返回数据之后,OkHttp将原始的结果交给Retrofit,Retrofit根据用户的需求对结果进行解析

与其他开源库对比

除了 Retrofit,如今 Android 中主流的网络请求框架有:

  • Android-Async-Http
  • Volly
  • OkHttp
    介绍
    介绍

几种网络请求库之间的区别对比

附:各个主流网络请求库的 Github 地址

Retrofit使用介绍

使用Retrofit的步骤共有7个:

步骤1:添加 Retrofit 库的依赖
步骤2:创建 接受服务器返回数据 的类
步骤3:创建 用于描述网络请求 的接口
步骤4:创建 Retrofit 实例
步骤5:创建 网络请求接口实例 并 配置网络请求参数
步骤6:发送网络请求(异步\同步)
    > 封装了 数据转换、线程切换的操作
步骤7:处理服务器返回的数据

接下来我们将这些步骤进行分解

步骤1:添加 Retrofit 库的依赖

1.在Gradle加入Retrofit库的依赖

由于Retrofit是基于OkHttp,所以还需要添加OkHttp库依赖

build.gradle

1
2
3
4
5
6
dependencies {
compile'com.squareup.retrofit2:retrofit:2.0.2'
// Retrofit库
compile 'com.squareup.okhttp3:okhttp:3.1.2'
// Okhttp库
}

2.添加 网络权限

AndroidManifest.xml

1
<uses-permission android:name="android.permission.INTERNET"/>

步骤2:创建 接受服务器返回数据 的类

Reception.java

1
2
3
4
5
public class Reception{
...
//根据返回数据的格式和数据解析方式(Json、XML等)定义
//下面会在实例中进行说明
}

步骤3:创建 用于描述网络请求 的接口

  • Retrofit将Http请求抽象成Java接口:采用注解描述网络请求的参数 和 配置网络请求参数

1.用 动态代理 动态 将该接口的注解“翻译”成一个Http请求,最后再执行Http请求
2.注:接口中的每个方法的参数都需要使用注解标注,否则会报错

_GetRequestInterface.interface

1
2
3
4
5
6
7
8
public interface GetRequest_Interface{
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall();
//@GET注解的作用:采用Get方法发送网络请求
//getCall() = 接受网络请求数据的方法
//其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类)
//如果想直接获得Responsebody中的内容,可以定义网络请求返回值为Call<ResponseBody>
}

下面详细介绍Retrofit网络请求接口 的注解类型
注解类型


注解说明

第一类:网络请求方法

详细说明:

a.@GET、@POST、@PUT、@DELETE、@HEAD

以上方法分别对应HTTP中的网络请求方式

1
2
3
4
5
6
7
public interface GetRequest_Interface {
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall();
// @GET注解的作用:采用Get方法发送网络请求
// getCall() = 接收网络请求数据的方法
// 其中返回类型为Call<*>,*是接收数据的类(即上面定义的Translation类)
}

此处特意说明URL的组成:Retrofit把 网络请求的URL分成了两部分设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 第1部分:在网络请求接口的注解设置
@GET("openapi.do?keyfrom=Yanzhikai&key=2032414398&type=data&doctype=json&version=1.1&q=car")
Call<Translation> getCall();
// 第2部分:在创建Retrofit实例时通过.baseUrl()设置
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("http://fanyi.youdao.com/") //设置网络请求的Url地址
.addConverterFactory(GsonConverterFactory.create()) //设置数据解析器
.build();
// 从上面看出:一个请求的URL可以通过 替换块 和 请求方法的参数 来进行动态的URL更新。
// 替换块是由 被{}包裹起来的字符串构成
// 即:Retrofit支持动态改变网络请求根目录

  • 网络请求的完整 Url = 在创建 Retrofit 实例时通过.baseUrl() 设置 + 网络请求接口的注解设置(下面称“path”)
  • 具体整合的规则如下:

    建议采用第三种方式来配置,并尽量使用同一种路径形式。

b.@HTTP

  • 作用:替换@GET、@POST、@PUT、@DELETE、@HEAD注解的作用 及 更多功能拓展
  • 具体使用:通过属性 method、path、hasBody进行设置
1
2
3
4
5
6
7
8
9
10
11
public interface GetRequest_Interface {
/**
* method:网络请求的方法(区分大小写)
* path:网络请求地址路径
* hasBody:是否有请求体
*/
@HTTP(method = "GET", path = "blog/{id}", hasBody = false)
Call<ResponseBody> getCall(@Path("id") int id);
// {id} 表示是一个变量
// method 的值 retrofit 不会做处理,所以要自行保证准确
}

第二类:标记

a.@FormUrlEncoded

  • 作用:表示发送form-encoded 的数据

    每个键值对需要用 @Filed 来注解键名,随后的对象需要提供值。

b.@Multipart

  • 作用:表示发送form-encoded 的数据(适用于 有文件 上传的场景)

    每个键值对需要用 @Part 来注解键名,随后的对象需要提供值。

具体使用如下:
_GetRequestInterface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public interface GetRequest_Interface {
/**
*表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
* <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
*/
@POST("/form")
@FormUrlEncoded
Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
/**
* {@link Part} 后面支持三种类型,{@link RequestBody}、{@link okhttp3.MultipartBody.Part} 、任意类型
* 除 {@link okhttp3.MultipartBody.Part} 以外,其它类型都必须带上表单字段({@link okhttp3.MultipartBody.Part} 中已经包含了表单字段的信息),
*/
@POST("/form")
@Multipart
Call<ResponseBody> testFileUpload1(@Part("name") RequestBody name, @Part("age") RequestBody age, @Part MultipartBody.Part file);
}
// 具体使用
GetRequest_Interface service = retrofit.create(GetRequest_Interface.class);
// @FormUrlEncoded
Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
// @Multipart
RequestBody name = RequestBody.create(textType, "Carson");
RequestBody age = RequestBody.create(textType, "24");
MultipartBody.Part filePart = MultipartBody.Part.createFormData("file", "test.txt", file);
Call<ResponseBody> call3 = service.testFileUpload1(name, age, filePart);

第三类:网络请求参数

详细说明

a.@Header & @Headers

  • 作用:添加请求头 & 添加不固定的请求头
  • 具体使用如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // @Header
    @GET("user")
    Call<User> getUser(@Header("Authorization") String authorization)
    // @Headers
    @Headers("Authorization: authorization")
    @GET("user")
    Call<User> getUser()
    // 以上的效果是一致的。
    // 区别在于使用场景和使用方式
    // 1. 使用场景:@Header用于添加不固定的请求头,@Headers用于添加固定的请求头
    // 2. 使用方式:@Header作用于方法的参数;@Headers作用于方法

b.@Body

  • 作用:以post方式 传递 自定义数据类型给服务器
  • 特别注意:如果提交的是一个Map,那么作用相当于@Field

    不过 Map 要经过FormBody.Builder类处理成为符合OkHttp格式的表单,如:

1
2
FormBody.Builder builder = new ForBody.Builder();
builder.add("key","value");

c.@Field & @FieldMap

  • 作用:发送 Post 请求 时提交请求的表单字段
  • 具体使用:与 @FormUrlEncoded 注解配合使用
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    public interface GetRequest_Interface {
    /**
    *表明是一个表单格式的请求(Content-Type:application/x-www-form-urlencoded)
    * <code>Field("username")</code> 表示将后面的 <code>String name</code> 中name的取值作为 username 的值
    */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrlEncoded1(@Field("username") String name, @Field("age") int age);
    /**
    * Map的key作为表单的键
    */
    @POST("/form")
    @FormUrlEncoded
    Call<ResponseBody> testFormUrlEncoded2(@FieldMap Map<String, Object> map);
    }
    // 具体使用
    // @Field
    Call<ResponseBody> call1 = service.testFormUrlEncoded1("Carson", 24);
    // @FieldMap
    // 实现的效果与上面相同,但要传入Map
    Map<String, Object> map = new HashMap<>();
    map.put("username", "Carson");
    map.put("age", 24);
    Call<ResponseBody> call2 = service.testFormUrlEncoded2(map);

d.@Part & @PartMap

e.@Query & @QueryMap

f.@Path

g.@Url

汇总

步骤4:创建 Retrofit 实例

步骤5:创建 网络请求接口实例 并 配置网络请求参数

步骤6:发送网络请求(异步\同步)

步骤7:处理服务器返回的数据